import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError } from 'axios';
import type { CreateAxiosOptions } from './defaultTransform.ts';
import type { RequestOptions, Result } from '#/axios.js';
import { AxiosCanceler } from './axiosCancel';
import axios from 'axios';
import _ from 'lodash';
import qs from 'qs';
import { ContentTypeEnum, RequestEnum } from '/@/enums/httpEnum';

// 创建一个类，其中包含了axios的各个属性和方法，并且在构造函数中传入axios实例，这样就可以在类中使用axios实例了。
export class CyAxios {
    private axiosInstance: AxiosInstance; // axios实例
    private readonly options: CreateAxiosOptions; // axios配置
    constructor(options: CreateAxiosOptions) { // 构造函数，用于对于该类接收参数，并将参数赋予实例上
        this.options = options; // 接收配置参数并赋予实例上
        this.axiosInstance = axios.create(options); // 创建axios实例并赋予实例上
        this.setupInterceptors(); // 初始化拦截器
    }

    private getTransform() {
        const { transform } = this.options;
        return transform;
    }

    getAxios(): AxiosInstance {
        return this.axiosInstance;
    }
    setHeader(headers: any): void {
        if (!this.axiosInstance) {
            return;
        }
        Object.assign(this.axiosInstance.defaults.headers, headers);
    }

    /**
     * @description: Interceptor configuration
     */
    private setupInterceptors() {
        const transform = this.getTransform();
        if (!transform) {
            return;
        }
        const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } = transform;

        const axiosCanceler = new AxiosCanceler();

        // 请求侦听器配置处理
        this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
            // If cancel repeat request is turned on, then cancel repeat request is prohibited
            // @ts-ignore
            const { ignoreCancelToken } = config.requestOptions;

            const ignoreCancel = ignoreCancelToken !== undefined ? ignoreCancelToken : this.options.requestOptions?.ignoreCancelToken;

            !ignoreCancel && axiosCanceler.addPending(config);
            if (requestInterceptors) {
                config = requestInterceptors(config, this.options);
            }
            return config;
        }, undefined);

        // 请求拦截器错误捕获
        requestInterceptorsCatch &&
            this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);

        // 响应结果拦截器处理
        this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
            res && axiosCanceler.removePending(res.config);
            if (responseInterceptors) {
                res = responseInterceptors(res);
            }
            return res;
        }, undefined);

        // 响应结果拦截器错误捕获
        responseInterceptorsCatch &&
            this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
    }

    /**
     * 文件上传
     */
    //   //--@updateBy-begin----author:liusq---date:20211117------for:增加上传回调参数callback------
    //   uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams, callback?: UploadFileCallBack) {
    //     //--@updateBy-end----author:liusq---date:20211117------for:增加上传回调参数callback------
    //     const formData = new window.FormData();
    //     const customFilename = params.name || 'file';

    //     if (params.filename) {
    //       formData.append(customFilename, params.file, params.filename);
    //     } else {
    //       formData.append(customFilename, params.file);
    //     }
    //     const glob = useGlobSetting();
    //     config.baseURL = glob.uploadUrl;
    //     if (params.data) {
    //       Object.keys(params.data).forEach((key) => {
    //         const value = params.data![key];
    //         if (Array.isArray(value)) {
    //           value.forEach((item) => {
    //             formData.append(`${key}[]`, item);
    //           });
    //           return;
    //         }

    //         formData.append(key, params.data[key]);
    //       });
    //     }

    //     return this.axiosInstance
    //       .request<T>({
    //         ...config,
    //         method: 'POST',
    //         data: formData,
    //         headers: {
    //           'Content-type': ContentTypeEnum.FORM_DATA,
    //           ignoreCancelToken: true,
    //         },
    //       })
    //       .then((res: any) => {
    //         //--@updateBy-begin----author:liusq---date:20210914------for:上传判断是否包含回调方法------
    //         if (callback?.success && isFunction(callback?.success)) {
    //           callback?.success(res?.data);
    //           //--@updateBy-end----author:liusq---date:20210914------for:上传判断是否包含回调方法------
    //         } else if (callback?.isReturnResponse) {
    //           //--@updateBy-begin----author:liusq---date:20211117------for:上传判断是否返回res信息------
    //           return Promise.resolve(res?.data);
    //           //--@updateBy-end----author:liusq---date:20211117------for:上传判断是否返回res信息------
    //         } else {
    //           if (res.data.success == true && res.data.code == 200) {
    //             createMessage.success(res.data.message);
    //           } else {
    //             createMessage.error(res.data.message);
    //           }
    //         }
    //       });
    //   }
    // // 支持表单数据
    supportFormData(config: AxiosRequestConfig) {
        const headers = config.headers || this.options.headers;
        const contentType = headers?.['Content-Type'] || headers?.['content-type'];

        if (contentType !== ContentTypeEnum.FORM_URLENCODED || !Reflect.has(config, 'data') || config.method?.toUpperCase() === RequestEnum.GET) {
          return config;
        }

        return {
          ...config,
          data: qs.stringify(config.data, { arrayFormat: 'brackets' }),
        };
      }

    get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
        return this.request({ ...config, method: 'GET' }, options);
    }

    post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
        return this.request({ ...config, method: 'POST' }, options);
    }

    put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
        return this.request({ ...config, method: 'PUT' }, options);
    }

    delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
        return this.request({ ...config, method: 'DELETE' }, options);
    }

    request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
        let conf: CreateAxiosOptions = _.cloneDeep(config);
        const transform = this.getTransform();

        const { requestOptions } = this.options;

        const opt: RequestOptions = Object.assign({}, requestOptions, options);

        const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
        if (beforeRequestHook) {
            conf = beforeRequestHook(conf, opt);
        }
        conf.requestOptions = opt;

        conf = this.supportFormData(conf);

        return new Promise((resolve, reject) => {
            this.axiosInstance
                .request<any, AxiosResponse<Result>>(conf)
                .then((res: AxiosResponse<Result>) => {
                    if (transformRequestHook) {
                        try {
                            const ret = transformRequestHook(res, opt);
                            //zhangyafei---添加回调方法
                            config.success && config.success(res.data);
                            //zhangyafei---添加回调方法
                            resolve(ret);
                        } catch (err) {
                            reject(err || new Error('request error!'));
                        }
                        return;
                    }
                    resolve(res as unknown as Promise<T>);
                })
                .catch((e: Error | AxiosError) => {
                    if (requestCatchHook) {
                        reject(requestCatchHook(e, opt));
                        return;
                    }
                    if (axios.isAxiosError(e)) {
                        // 在此处重写来自axios的错误消息
                    }
                    reject(e);
                });
        });
    }

      /**
       * 【用于评论功能】自定义文件上传-请求
       * @param url
       * @param formData
       */
    //   uploadMyFile<T = any>(url, formData) {
    //     const glob = useGlobSetting(); .env.development里的所有配置
    //     return this.axiosInstance.request<T>({
    //       url: url,
    //       baseURL: glob.uploadUrl,
    //       method: 'POST',
    //       data: formData,
    //       headers: {
    //         'Content-type': ContentTypeEnum.FORM_DATA,
    //         ignoreCancelToken: true,
    //       },
    //     });
    //   }
}